package cn.mw.cmdb.monitorview.service.impl;

import cn.mw.cmdb.entity.InstanceInfo;
import cn.mw.cmdb.monitorview.annotations.NotesInfo;
import cn.mw.cmdb.monitorview.entity.MwBladeDto;
import cn.mw.cmdb.monitorview.entity.MwKnifeBlockDto;
import cn.mw.cmdb.monitorview.param.MwKnifeBlockParam;
import cn.mw.cmdb.monitorview.service.BladeHandler;
import cn.mw.cmdb.monitorview.service.MwKnifeBlockViewService;
import cn.mw.cmdb.param.InstanceSearchParam;
import cn.mw.cmdb.param.zabbixResult.ItemApplication;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.util.SeverityUtils;
import cn.mw.main.api.common.ZabbixDubboService;
import cn.mw.microMonitorCommon.constants.ZabbixApiConstants;
import cn.mw.microMonitorCommon.entity.zabbix.MWZabbixAPIResult;
import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static cn.mw.cmdb.service.impl.InstanceViewImpl.mwInstanceNameKey;

/**
 * @description 刀框视图
 */
@Slf4j
@Service
public class MwKnifeBlockViewServiceImpl implements MwKnifeBlockViewService {

    @DubboReference(check = false, timeout = 120000)
    public ZabbixDubboService zabbixDubboService;

    private CmdbServiceManage cmdbServiceManage;

    private final String NODE_ID = "Node_ID";

    private final List<String> BLADE_ITEM_NAMES = Arrays.asList("CPU_MODEL","DISK_ARRAY_MODEL","MEMORY_STATE","DISK_STATE","FAN_STATE","POWER_STATE","TEMPERATURE_STATE");

    private final List<String> KNIFE_BLOCK_ITEM_NAMES = Arrays.asList("SYSTEM_UPTIME","Product Version","Global System Status","SYSTEM_DESCR");

    public MwKnifeBlockViewServiceImpl(CmdbServiceManage cmdbServiceManage) {
        this.cmdbServiceManage = cmdbServiceManage;
    }

    @Override
    public List<MwBladeDto> getBladeInfo(MwKnifeBlockParam knifeBlockParam) throws Exception {
        log.info("MwKnifeBlockViewServiceImpl{} getBladeAssetsInfo() knifeBlockParam>>>"+knifeBlockParam);
        List<MwBladeDto> bladeAssetsInfo = new ArrayList<>();
        //查询刀箱下面的nodeID
        MWZabbixAPIResult mwZabbixAPIResult = zabbixDubboService.getZabbixApiResult(ZabbixApiConstants.ITEM_GET_BY_SEARCH, knifeBlockParam.getServerId(), NODE_ID, knifeBlockParam.getHostId());
        log.info("MwKnifeBlockViewServiceImpl{} getBladeAssetsInfo() mwZabbixAPIResult>>>"+mwZabbixAPIResult);
        if(mwZabbixAPIResult == null ||mwZabbixAPIResult.isFail()){return bladeAssetsInfo;}
        //获取所有的nodeId
        List<ItemApplication> itemApplications = JSONArray.parseArray(String.valueOf(mwZabbixAPIResult.getData()), ItemApplication.class);
        log.info("MwKnifeBlockViewServiceImpl{} getBladeAssetsInfo() itemApplications>>>"+itemApplications);
        if(CollectionUtils.isEmpty(itemApplications)){return bladeAssetsInfo;}
        List<String> nodeIds = itemApplications.stream().filter(item -> StringUtils.isNotEmpty(item.getLastvalue())).map(s -> s.getLastvalue()).collect(Collectors.toList());
        log.info("MwKnifeBlockViewServiceImpl{} getBladeAssetsInfo() nodeIds>>>"+nodeIds);
        //根据nodeId查询刀片资产信息
        List<InstanceInfo> instanceInfos = getBladeAssetsInfo(nodeIds);
        if(CollectionUtils.isEmpty(instanceInfos)){return bladeAssetsInfo;}
        for (InstanceInfo instanceInfo : instanceInfos) {
            MwBladeDto bladeDto = new MwBladeDto();
            bladeDto.extractFrom(instanceInfo);
            bladeAssetsInfo.add(bladeDto);
        }
        if(CollectionUtils.isEmpty(bladeAssetsInfo)){return bladeAssetsInfo;}
        Map<String, String> assetsMap = bladeAssetsInfo.stream().collect(Collectors.toMap(s -> s.getHostId() + s.getServerId(), s -> s.getInstanceId()));
        Map<Integer, List<String>> groupMap = bladeAssetsInfo.stream().filter(item->item.getServerId() != null &&  item.getServerId() != 0)
                .collect(Collectors.groupingBy(MwBladeDto::getServerId, Collectors.mapping(MwBladeDto::getHostId, Collectors.toList())));
        List<ItemApplication> bladeItemInfos = new ArrayList<>();
        //获取刀片的监控信息
        for (Map.Entry<Integer, List<String>> entry : groupMap.entrySet()) {
            MWZabbixAPIResult result = zabbixDubboService.getZabbixApiResult(ZabbixApiConstants.ITEM_GET_BY_SEARCH, entry.getKey(), BLADE_ITEM_NAMES, entry.getValue());
            log.info("MwKnifeBlockViewServiceImpl{} getBladeAssetsInfo() result>>>"+result);
            if(mwZabbixAPIResult == null ||mwZabbixAPIResult.isFail()){continue;}
            List<ItemApplication> applications = JSONArray.parseArray(String.valueOf(result.getData()), ItemApplication.class);
            if(CollectionUtils.isEmpty(applications)){continue;}
            for (ItemApplication application : applications) {
                application.setAssetsId(assetsMap.get(application.getHostid()+entry.getKey()));
            }
            bladeItemInfos.addAll(applications);
        }
        log.info("MwKnifeBlockViewServiceImpl{} getBladeAssetsInfo() getBladeInfo>>>"+bladeItemInfos);
        //按照资产分组
        Map<String, List<ItemApplication>> listMap = bladeItemInfos.stream().collect(Collectors.groupingBy(item -> item.getAssetsId()));
        Map<String, MwBladeDto> bladeDtoMap = bladeAssetsInfo.stream().collect(Collectors.toMap(s -> s.getInstanceId(), s -> s));
        BladeHandler bladeHandler = new BladeHandler();
        List<MwBladeDto> newBladeDtos = new ArrayList<>();
        for (Map.Entry<String, List<ItemApplication>> entry : listMap.entrySet()) {
            List<ItemApplication> applications = entry.getValue();
            MwBladeDto bladeDto = bladeDtoMap.get(entry.getKey());
            if(CollectionUtils.isEmpty(applications) || bladeDto == null){continue;}
            bladeHandler.handler(bladeDto,applications);
            newBladeDtos.add(bladeDto);
        }
        return newBladeDtos;
    }

    @Override
    public MwKnifeBlockDto getKnifeBlockBasicMonitorInfo(MwKnifeBlockParam knifeBlockParam) throws Exception {
        MwKnifeBlockDto knifeBlockDto = new MwKnifeBlockDto();
        MWZabbixAPIResult mwZabbixAPIResult = zabbixDubboService.getZabbixApiResult(ZabbixApiConstants.ITEM_GET_BY_SEARCH, knifeBlockParam.getServerId(), KNIFE_BLOCK_ITEM_NAMES, knifeBlockParam.getHostId());
        log.info("MwKnifeBlockViewServiceImpl{} getKnifeBlockBasicMonitorInfo() mwZabbixAPIResult>>>>"+mwZabbixAPIResult);
        if(mwZabbixAPIResult == null ||mwZabbixAPIResult.isFail()){return knifeBlockDto;}
        List<ItemApplication> itemApplications = JSONArray.parseArray(String.valueOf(mwZabbixAPIResult.getData()), ItemApplication.class);
        if(CollectionUtils.isEmpty(itemApplications)){return knifeBlockDto;}
        for (ItemApplication itemApplication : itemApplications) {
            setFieldInfo(MwKnifeBlockDto.class,knifeBlockDto,itemApplication);
        }
        log.info("MwKnifeBlockViewServiceImpl{} getKnifeBlockBasicMonitorInfo() knifeBlockDto>>>>"+knifeBlockDto);
        //数据处理
        if(StringUtils.isNotEmpty(knifeBlockDto.getRunTime())){
            String time = knifeBlockDto.getRunTime();
            knifeBlockDto.setRunTime(SeverityUtils.getLastTime(Long.parseLong(time)));;
        }
        return knifeBlockDto;
    }

    @Override
    public List<MwBladeDto> getAllBladeBasicInfo(MwKnifeBlockParam knifeBlockParam) throws Exception {
        List<MwBladeDto> bladeAssetsInfo = new ArrayList<>();
        //查询刀箱下面的nodeID
        MWZabbixAPIResult mwZabbixAPIResult = zabbixDubboService.getZabbixApiResult(ZabbixApiConstants.ITEM_GET_BY_SEARCH, knifeBlockParam.getServerId(), NODE_ID, knifeBlockParam.getHostId());
        if(mwZabbixAPIResult == null ||mwZabbixAPIResult.isFail()){return bladeAssetsInfo;}
        //获取所有的nodeId
        List<ItemApplication> itemApplications = JSONArray.parseArray(String.valueOf(mwZabbixAPIResult.getData()), ItemApplication.class);
        if(CollectionUtils.isEmpty(itemApplications)){return bladeAssetsInfo;}
        List<String> nodeIds = itemApplications.stream().filter(item -> StringUtils.isNotEmpty(item.getLastvalue())).map(s -> s.getLastvalue()).collect(Collectors.toList());
        //根据nodeId查询刀片资产信息
        List<InstanceInfo> instanceInfos = getBladeAssetsInfo(nodeIds);
        if(CollectionUtils.isEmpty(instanceInfos)){return bladeAssetsInfo;}
        for (InstanceInfo instanceInfo : instanceInfos) {
            MwBladeDto bladeDto = new MwBladeDto();
            bladeDto.extractFrom(instanceInfo);
            bladeAssetsInfo.add(bladeDto);
        }
        return bladeAssetsInfo;
    }

    private List<InstanceInfo> getBladeAssetsInfo(List<String> nodeIds) throws Exception {
        InstanceServiceImpl service = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
        Map data = new HashMap();
        data.put(mwInstanceNameKey, nodeIds);
        instanceSearchParam.setData(data);
        instanceSearchParam.convert();
        log.info("MwKnifeBlockViewServiceImpl{} getBladeAssetsInfo() instanceSearchParam>>>"+instanceSearchParam);
        List<InstanceInfo> instanceInfoList = service.doSelectList(instanceSearchParam);
        log.info("MwKnifeBlockViewServiceImpl{} getBladeAssetsInfo() instanceInfoList>>>"+instanceInfoList);
        return instanceInfoList;
    }


    private void setFieldInfo(Class cls,Object obj,ItemApplication itemApplication) throws IllegalAccessException {
        String name = itemApplication.getName();
        if(name.contains("[")){
            name = name.split("]")[1];
        }
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            if(!field.isAnnotationPresent(NotesInfo.class)){continue;}
            NotesInfo notesInfo = field.getAnnotation(NotesInfo.class);
            if(!notesInfo.itemName().equals(name)){continue;}
            field.setAccessible(true);
            Object value = field.get(obj);
            String lastvalue = itemApplication.getLastvalue();
            Boolean numeric = isNumeric(lastvalue);
            if(!numeric){
                field.set(obj,lastvalue);
                continue;
            }
            if(value != null){
                String strValue = value.toString();
                field.set(obj, new BigDecimal(lastvalue).add(new BigDecimal(strValue)).toString());
            }else{
                field.set(obj,lastvalue);
            }
        }
    }


    public Boolean isNumeric(String value) {
        // 定义数字的正则表达式，允许负号和小数点
        String numericRegex = "^[-+]?[0-9]*\\.?[0-9]+$";
        // 创建 Pattern 对象
        Pattern pattern = Pattern.compile(numericRegex);
        // 创建 Matcher 对象
        Matcher matcher = pattern.matcher(value);
        // 判断是否匹配
        if(!matcher.matches()){
            return false;
        }
        return true;
    }

}
